/* type_descriptor.h */

#ifndef DODO_TYPE_DESCRIPTOR_H
#define DODO_TYPE_DESCRIPTOR_H
#include <iostream>

template <class T>
class type_descriptor;

template <class T>
std::ostream& operator<< (std::ostream& s, const type_descriptor<T> &t);

template <class T>
class type_descriptor
{
public:
	friend std::ostream& operator<< <T> (std::ostream& s, const type_descriptor<T> &);
};


template <class T>
std::ostream& operator<< (std::ostream& s, const type_descriptor<T> &t)
{
	return s;
}

template<class T>
std::ostream& operator<< (std::ostream& s, const type_descriptor<T*> &)
{
	s << "pointer to " << type_descriptor< T >();
	return s;
}

template<class T>
std::ostream& operator<< (std::ostream& s, const type_descriptor<T[]> &)
{
	s << "array of " << type_descriptor< T >();
	return s;
}

template<>
std::ostream& operator<< (std::ostream& s, const type_descriptor<char> &)
{
	s << "char";
	return s;
}

template<>
std::ostream& operator<< (std::ostream& s, const type_descriptor<int> &)
{
	s << "int";
	return s;
}

template<>
std::ostream& operator<< (std::ostream& s, const type_descriptor<float> &)
{
	s << "float";
	return s;
}

template<>
std::ostream& operator<< (std::ostream& s, const type_descriptor<double> &)
{
	s << "double";
	return s;
}

template<>
std::ostream& operator<< (std::ostream& s, const type_descriptor<bool> &)
{
	s << "bool";
	return s;
}

template<>
std::ostream& operator<< (std::ostream& s, const type_descriptor<void> &)
{
	s << "void";
	return s;
}
#endif //DODO_TYPE_DESCRIPTOR_H

